#ifndef _RawUrl_H_
#define _RawUrl_H_

#include "strKit.hpp"
class RawUrl
{
public:
    //@brief 资源类型
    typedef enum tag_Type
    {
        ETYPE_HTML, // 超文本标记语言
        ETYPE_IMAGE // 图像
    } ETYPE;
    std::string _strUrl; //统一资源定位符
    ETYPE _type;//类型
    int _depth;//深度
    //@brief 构造器 < [in] 统一资源定位符字符串 // [in] 资源类型 // [in] 链接深度
    RawUrl(const std::string &strUrl, ETYPE type = ETYPE_HTML, int depth = 0)
        : _strUrl(strUrl) // 初始化统一资源定位符字符串
        ,_type(type) // 初始化资源类型
        ,_depth(depth) // 初始化链接深度
    {}

    /// @brief 规格化
    /// @retval true  成功
    /// @retval false 失败
    /// @remark 删除协议标签(http://或https://)和结尾分隔符(/)
    static bool normalized(std::string &strUrl) //< [in,out] 待规格化统一资源定位符字符串
    {
        // 将待规格化统一资源定位符字符串复制到临时变量
        std::string strTmp = strUrl;
        // 修剪临时变量中的待规格化统一资源定位符字符串
        StrKit::trim(strTmp);

        // 若待规格化统一资源定位符字符串为空串
        if (strTmp.empty()) return false;
        // 若待规格化统一资源定位符字符串以"http://"开头
        if (!strTmp.find("http://", 0)) strTmp = strTmp.substr(7);  // 剪除该协议子串
        // 否则
        else
        { // 若待规格化统一资源定位符字符串以"https://"开头
            if (!strTmp.find("https://", 0)) strTmp = strTmp.substr(8); // 剪除该协议子串
            // 若待规格化统一资源定位符字符串以'/'结尾
            // 剪除该路径分隔符
            if (*(strTmp.end() - 1) == '/') strTmp.erase(strTmp.end() - 1);
            // 若待规格化统一资源定位符字符串过长(大于128个字符)
            if (strTmp.size() > 128) return false;
            // 将临时变量中已规格化的统一资源定位符字符串复制到参数中
        }
        strUrl = strTmp;
        return true;
    }
};

/// @brief 解析统一资源定位符
class DnsUrl : public RawUrl
{
public:
    std::string _domain;//域名
    std::string _path;//资源路径
    std::string _ip;//服务器ip地址
    uint64_t _port;//端口号
public:
    /// @brief 构造器
    explicit DnsUrl(
        RawUrl const &rawUrl ///< [in] 原始统一资源定位符
    )
    : RawUrl (rawUrl)
    { 
        // 初始化原始统一资源定位符基类子对象
        // 在从基类继承的统一资源定位符字符串中查找第一个'/'
        std::string::size_type pos = _strUrl.find_first_of('/');
        // 若没找到  整个统一资源定位符字符串都认作服务器域名
        if (pos == std::string::npos) _domain = _strUrl;
        // 否则
        else
        {
            //统一资源定位符字符串中第一个'/'之前为服务器域名
            _domain = _strUrl.substr(0, pos);
            //之后为资源路径。注意作为服务器域名和
            //资源路径之间分隔符的'/'不放在路径中
            _path = _strUrl.substr(pos + 1);
        }
        // 在服务器域名中查找最后一个':'。若找到了，则将其后
        // 的子串转换为整数作为服务器通信端口；若没有找到或转
        // 换后的端口号非法，则将服务器通信端口设置为缺省值80
        if ((pos = _domain.find_last_of(':')) == std::string::npos ||
            !(_port = atoi(_domain.substr(pos + 1).c_str())))
            _port = 80;
    }
    /// @return 文件名字符串 /// @brief 转换为文件名字符串
    std::string toFilename(void) const
    {
        // 用服务器域名初始化文件名字符串
        std::string filename = _domain;
        // 若资源路径非空 // 在文件名字符串中追加"/"和资源路径
        if (! _path.empty ()) (filename += "/") += _path;
        // 逐个查找文件名字符串中的每个'/'
        for (std::string::size_type pos = 0; (pos = filename.find ('/', pos)) != std::string::npos; ++pos)
        {   
            // 若找到，则将其替换为"_"
            filename.replace (pos, 1, "_");
        }
        // 若资源类型为超文本标记语言
        if (_type == ETYPE_HTML) 
        {
            // 在文件名字符串中查找最后一个'.'
            std::string::size_type pos = filename.find_last_of ('.');
            // 若没找到，或虽然找到但连同其后
            // 的子串既不是".htm"也不是".html"
            if (pos == std::string::npos || (filename.substr (pos) != ".htm" && filename.substr (pos) != ".html"))
                filename += ".html"; // 在文件名字符串中追加扩展名".html"
        }
        // 返回文件名字符串
        return filename;

    }
    /// @brief 添加域名
    /// @retval true  成功
    /// @retval false 失败
    //< [in,out] 待加域名统一资源定位符字符串
    bool attachDomain( std::string &strUrl) const 
    {
        // 若待加域名统一资源定位符字符串以"http"开头，说明已有域名
        if (! strUrl.find ("http", 0)) return true;
        // 若待加域名统一资源定位符字符串为空，或首字符不是'/'
        if (strUrl.empty () || strUrl[0] != '/') return false;
        // 将服务器域名插到待加域名统一资源定位符字符串首字符之前
        strUrl.insert (0, _domain);
        // 返回成功
        return true;
    }
};

#endif //_RawUrl_H_